package com.ttxs.generator.output.js;

import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.util.FileUtils;
import com.ttxs.generator.engine.CustomFreemarker;
import com.ttxs.generator.output.Output;
import com.ttxs.generator.util.PathUtils;
import com.ttxs.generator.util.TableInfoUtils;
import com.ttxs.generator.vo.FormBean;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.io.*;
import java.util.*;

import static com.ttxs.generator.util.Constants.LINE_SEPARATOR;
import static com.ttxs.generator.util.Constants.ROUTER_START_LINE_FLAG;

@Slf4j
public class RouterIndex implements Output {

    /**
     * 输出静态路由的index.js文件，输出路径为：src/router/index.js
     *
     * @param templateEngine
     */
    @Override
    public void write(CustomFreemarker templateEngine) throws IOException {
        ConfigBuilder config = templateEngine.getConfigBuilder();
        FormBean formBean = templateEngine.formBean();
        List<TableInfo> tableInfoList = config.getTableInfoList();
        String routerJsPath = PathUtils.get(PathUtils.Vue.router, formBean.getVueProjectPath());
        File routerJsFile = new File(routerJsPath + File.separator + "index.js");
        FileUtils.forceMkdirParent(routerJsFile);

        Set<Route> newRoutes = getNewRoutes(formBean, tableInfoList);
        // 路由转换成string
        StringBuilder content = new StringBuilder();
        for (Route route : newRoutes) {
            content.append("{").append(LINE_SEPARATOR);
            if(Objects.nonNull(route.getPath())) content.append("\t").append(route.getPath()).append(LINE_SEPARATOR);
            if(Objects.nonNull(route.getName())) content.append("\t").append(route.getName()).append(LINE_SEPARATOR);
            if(Objects.nonNull(route.getComponent())) content.append("\t").append(route.getComponent()).append(LINE_SEPARATOR);
            if(Objects.nonNull(route.getRedirect())) content.append("\t").append(route.getRedirect()).append(LINE_SEPARATOR);
            if(Objects.nonNull(route.getChildren())) content.append("\t").append(route.getChildren()).append(LINE_SEPARATOR);
            content.append("},").append(LINE_SEPARATOR);
        }
        write(routerJsFile, content);
    }

    private void write(File routerJsFile, StringBuilder content) throws IOException {
        File tempFile = File.createTempFile(UUID.randomUUID().toString(), ".tmp");
        String line;
        try (BufferedWriter out = new BufferedWriter(new FileWriter(tempFile));
            BufferedReader in = new BufferedReader(new FileReader(routerJsFile))) {
            while ((line = in.readLine()) != null) {
                out.write(line + LINE_SEPARATOR);
                if(ROUTER_START_LINE_FLAG.equals(line)) {
                    out.write(content.toString());
                }
            }
            out.flush();
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw ex;
        }
        routerJsFile.delete();
        tempFile.renameTo(routerJsFile);
        tempFile.delete();
    }

    private Set<Route> getNewRoutes(FormBean formBean, List<TableInfo> tableInfoList) {
        Set<Route> routes = new TreeSet<>();
        String artifactId = formBean.getArtifactId();
        String platformName = formBean.getPlatformName();
        for (TableInfo tableInfo : tableInfoList) {
            if (tableInfo.isHavePrimaryKey() && !TableInfoUtils.isCompositeKey(tableInfo)) {
                String entityName = StringUtils.uncapitalize(tableInfo.getEntityName());
                String path = "path: '/" + artifactId + "/" + entityName + "',";
                String component = "component: Layout,";
                String children = formBean.isSpringCloud()
                        ? "children: [{name: '" + entityName + "', path:'', component: () => import('@/views/" + platformName + "/" + artifactId + "/" + entityName + "/index.vue')}]"
                        : "children: [{name: '" + entityName + "', path:'', component: () => import('@/views/" + artifactId + "/" + entityName + "/index.vue')}]";
                routes.add(new Route(path, null, component, children));
            }
        }
        return routes;
    }

    @Data
    @NoArgsConstructor
    private static class Route implements Comparable<Route> {
        private String path;
        private String name;
        private String redirect;
        private String component;
        private String children;

        public Route(String path, String name, String component, String children) {
            this.path = path;
            this.name = name;
            this.component = component;
            this.children = children;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Route route = (Route) o;
            return Objects.equals(path, route.path);
        }

        @Override
        public int hashCode() {
            return Objects.hash(path);
        }

        @Override
        public int compareTo(Route o) {
            return path.compareTo(o.path);
        }

    }

}
